package com.think.cloud.thinkshop.mall.service.aftersales.impl;


import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.think.cloud.thinkshop.common.constant.aftersales.AfterSalesConstants;
import com.think.cloud.thinkshop.mall.controller.app.aftersales.vo.*;
import com.think.cloud.thinkshop.mall.convert.aftersales.AfterSalesConvert;
import com.think.cloud.thinkshop.mall.domain.aftersales.AfterSales;
import com.think.cloud.thinkshop.mall.domain.aftersales.AfterSalesDetail;
import com.think.cloud.thinkshop.mall.domain.aftersales.AfterSalesLog;
import com.think.cloud.thinkshop.mall.domain.order.Order;
import com.think.cloud.thinkshop.mall.domain.order.OrderDetail;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesDelEnum;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesOperateTypeEnum;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesSearchTypeEnum;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesStatusEnum;
import com.think.cloud.thinkshop.mall.enums.logisticslog.LogisticsOrderTypeEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderDetailStateEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderOperateUserTypeEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderStatusEnum;
import com.think.cloud.thinkshop.mall.mapper.aftersales.AfterSalesDetailMapper;
import com.think.cloud.thinkshop.mall.mapper.aftersales.AfterSalesMapper;
import com.think.cloud.thinkshop.mall.mapper.order.OrderDetailMapper;
import com.think.cloud.thinkshop.mall.mapper.order.OrderMapper;
import com.think.cloud.thinkshop.mall.service.aftersales.AppAfterSalesService;
import com.think.cloud.thinkshop.mall.service.aftersales.IAfterSalesLogService;
import com.think.cloud.thinkshop.mall.service.order.ILogisticsLogService;
import com.think.cloud.thinkshop.mall.service.websitesetting.IWebsiteSettingService;
import com.think.cloud.thinkshop.mall.utils.RedisUtils;
import com.think.common.core.exception.util.ServiceExceptionUtil;
import com.think.common.core.utils.DateUtils;
import com.think.common.core.utils.PageUtils;
import com.think.common.core.web.page.TableDataInfo;
import com.think.common.security.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesOperateTypeEnum.*;
import static com.think.common.core.exception.enums.ErrorCode.*;


/**
 * App售后记录Service业务层处理
 *
 * @author zkthink
 * @date 2024-06-12
 */
@Service
public class AppAfterSalesServiceImpl implements AppAfterSalesService {

    @Autowired
    private AfterSalesMapper afterSalesMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AfterSalesDetailMapper afterSalesDetailMapper;

    @Autowired
    private IAfterSalesLogService afterSalesLogService;

    @Autowired
    private ILogisticsLogService logisticsLogService;

    @Autowired
    private IWebsiteSettingService websiteSettingService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long apply(AppApplyAfterSalesReqVO vo) {
        // 查询订单信息
        Order order = this.getOrderById(vo.getOrderId());
        Long userId = vo.getUserId();
        // 校验是否为本人订单
        verifyMyselfOrder(userId, order.getUserId());
        // 校验订单状态是否可申请退款
        if (!checkAfterState(order.getStatus(), order.getCompleteTime()))
            throw ServiceExceptionUtil.exception(ORDER_NOT_AFTER_SALES_ERROR);
        // 构建售后订单
        AfterSales afterSales = AfterSalesConvert.INSTANCE.convert(vo);
        // 生成售后单号
        afterSales.setAfterSalesCode(getAfterSalesCode());
        // 发货标识
        boolean sendFlag = OrderStatusEnum.AWAITING_SHIPMENT.getValue().equals(order.getStatus());
        // 退款金额
        BigDecimal refundAmount = BigDecimal.ZERO;
        // 商品总计
        BigDecimal totalPrice = BigDecimal.ZERO;
        // 优惠金额
        BigDecimal couponPrice = BigDecimal.ZERO;
        // 退货商品数
        Integer refundNumber = 0;
        // 退税费
        BigDecimal taxation = BigDecimal.ZERO;
        // 退运费
        BigDecimal totalPostage = BigDecimal.ZERO;
        // 查询可售后订单明细
        List<OrderDetail> orderDetails = getOrderDetailList(vo.getOrderId(), null);
        // 判断是否存在可售后订单明细
        if (CollectionUtils.isEmpty(orderDetails)) throw ServiceExceptionUtil.exception(ORDER_NOT_AFTER_SALES_ERROR);
        Map<Long, List<OrderDetail>> orderDetailMap =
                orderDetails.stream().collect(Collectors.groupingBy(OrderDetail::getSkuId));

        List<OrderDetail> updateOrderDetailList = new ArrayList<>();
        for (AppAfterSalesDetailReqVO afterSalesDetail : vo.getDetails()) {
            List<OrderDetail> skuOrderDetails = orderDetailMap.get(afterSalesDetail.getSkuId());
            // 退款不可超过购买数量
            if (CollectionUtils.isEmpty(skuOrderDetails) || skuOrderDetails.size() < afterSalesDetail.getNumber()) {
                throw ServiceExceptionUtil.exception(ORDER_REFUND_NUMBER_LACK_ERROR);
            }
            OrderDetail orderDetail = skuOrderDetails.get(0);
            BigDecimal number = new BigDecimal(afterSalesDetail.getNumber());
            refundAmount = refundAmount.add(orderDetail.getPrice().multiply(number));   // 累加退款金额
            totalPrice = totalPrice.add(orderDetail.getOriginalPrice().multiply(number));   // 累加商品总价
            couponPrice = couponPrice.add(orderDetail.getOriginalPrice()
                    .subtract(orderDetail.getPrice()).multiply(number));   // 累加优惠金额
            refundNumber = refundNumber + afterSalesDetail.getNumber(); // 累加退货数
            // 未发货退税
            if (sendFlag) taxation = taxation.add(orderDetail.getTaxation().multiply(number));  // 计算应退税费
            updateOrderDetailList.addAll(skuOrderDetails.subList(0, afterSalesDetail.getNumber()));
        }
        // 未发货且全部退货退运费和运费税费
        if (sendFlag && CollectionUtils.isEmpty(getOrderDetailList(vo.getOrderId(),
                updateOrderDetailList.stream().map(OrderDetail::getId).collect(Collectors.toList())))) {
            totalPostage = order.getTotalPostage();
            taxation = taxation.add(order.getPostageTaxation());
        }
        refundAmount = refundAmount.add(taxation).add(totalPostage);

        // 减去积分抵扣的金额
        BigDecimal integralDeduct = order.getIntegralDeduct();
        if (integralDeduct != null) {
            refundAmount = refundAmount.subtract(integralDeduct);
        }
        afterSales.setRefundAmount(refundAmount);
        afterSales.setTotalPrice(totalPrice);
        afterSales.setCouponPrice(couponPrice);
        afterSales.setNumber(refundNumber);
        afterSales.setTaxation(taxation);
        afterSales.setTotalPostage(totalPostage);
        // 保存退款订单
        afterSalesMapper.insert(afterSales);
        Long afterSalesId = afterSales.getId();
        List<AfterSalesDetail> afterSalesDetails = new ArrayList<>();
        // 修改订单明细
        updateOrderDetailList.forEach(res -> {
            res.setAfterSalesId(afterSalesId);
            res.setState(OrderDetailStateEnum.IN_AFTER_SALES.getValue());
            afterSalesDetails.add(AfterSalesDetail.builder().orderDetailId(res.getId()).afterSalesId(afterSalesId).build());
        });
        orderDetailMapper.batchUpdate(updateOrderDetailList);
        // 保存售后明细
        afterSalesDetailMapper.batchInsert(afterSalesDetails);
        // 保存售后操作记录
        this.saveAfterSalesOperateLog(afterSalesId, OrderOperateUserTypeEnum.USER, userId, SUBMIT_APPLICATION);
        return afterSalesId;
    }

    @Override
    public boolean checkAfterState(Integer status, Date completeTime) {
        return Arrays.asList(
                OrderStatusEnum.AWAITING_SHIPMENT.getValue(),
                OrderStatusEnum.AWAITING_RECEIPT.getValue(),
                OrderStatusEnum.COMPLETED.getValue()
        ).contains(status) && passLastSaleAfterTime(completeTime);
    }

    /**
     *  判断是否在售后时间内
     * @param orderCompleteTime 订单完成时间 为空说明订单未完成,允许售后
     * @return true:  是   false:没有
     */
    private boolean passLastSaleAfterTime(Date orderCompleteTime) {
        Integer closeAfterSale = websiteSettingService.getCache().getCloseAfterSale();
        return orderCompleteTime == null || DateUtils.addDays(orderCompleteTime, closeAfterSale).after(DateUtils.getNowDate());
    }


    // 保存售后操作记录
    private void saveAfterSalesOperateLog(Long afterSalesId, OrderOperateUserTypeEnum userType,
                                          Long userId, AfterSalesOperateTypeEnum operateType) {
        AfterSalesLog afterSalesLog = AfterSalesLog.builder()
                .afterSalesId(afterSalesId)
                .userType(userType.getValue())
                .userId(userId)
                .operateType(operateType.getValue())
                .build();
        afterSalesLog.setCreateBy(SecurityUtils.getUsername());
        afterSalesLogService.insertSalesLog(afterSalesLog);
    }

    // 查询可售后订单明细
    private List<OrderDetail> getOrderDetailList(Long orderId, List<Long> ids) {
        return orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>()
                .eq(OrderDetail::getOrderId, orderId)
                .notIn(CollectionUtils.isNotEmpty(ids), OrderDetail::getOrderId, orderId)
                .eq(OrderDetail::getState, OrderDetailStateEnum.NORMAL.getValue()));
    }

    /**
     * 生成售后单号
     */
    private String getAfterSalesCode() {
        return RedisUtils.getSerialNumber(AfterSalesConstants.AFTER_SALES_CODE_PREFIX,
                AfterSalesConstants.ORDER_CODE_REDIS_KEY, AfterSalesConstants.DATE_FORMAT,
                AfterSalesConstants.NUMBER_FORMAT);
    }

    @Override
    public AppAfterSalesInfoRespVO get(Long afterSalesId) {
        AppAfterSalesInfoRespVO result = AfterSalesConvert.INSTANCE.convert(getAfterSalesById(afterSalesId));
        List<AppAfterSalesDetailRespVO> afterSalesDetails = this.findAfterSalesOrderDetailList(Arrays.asList(afterSalesId));
//        afterSalesDetails.forEach(res -> res.setImage(res.getImage().split(",")[0]));
        afterSalesDetails.forEach(res -> {
            String image = res.getImage();
            if (image == null || image.isEmpty()) {
                res.setImage(res.getProductImage().split(",")[0]);
            }
        });
        // 查询售后订单明细
        result.setDetails(afterSalesDetails);
        // 查询售后操作日志
        result.setLogs(afterSalesLogService.getAfterSalesLogList(afterSalesId));
        // 查询订单信息
        Order order = this.getOrderById(result.getOrderId());
        result.setOrderCode(order.getOrderCode());
        result.setUseIntegral(order.getUseIntegral());
        result.setIntegralDeduct(order.getIntegralDeduct());
        return result;
    }

    private Order getOrderById(Long orderId) {
        return orderMapper.getOrderById(orderId);
    }

    // 查询订单明细
    private List<AppAfterSalesDetailRespVO> findAfterSalesOrderDetailList(List<Long> afterSalesIds) {
        return orderDetailMapper.selectAfterSalesOrderDetailList(afterSalesIds);
    }

    @Override
    public TableDataInfo list(AppAfterSalesPageReqVO vo) {
        List<AppAfterSalesPageRespVO> result = afterSalesMapper.selectAfterSaleList(setStates(vo));
        if (CollectionUtils.isNotEmpty(result)) {
            List<Long> afterSalesIds = result.stream().map(AppAfterSalesPageRespVO::getId).collect(Collectors.toList());
            // 查询订单明细
            List<AppAfterSalesDetailRespVO> afterSalesDetailRespVOS = this.findAfterSalesOrderDetailList(afterSalesIds);
//            afterSalesDetailRespVOS.forEach(res -> res.setImage(res.getImage().split(",")[0]));
            afterSalesDetailRespVOS.forEach(res -> {
                String image = res.getImage();
                if (image == null || image.isEmpty()) {
                    res.setImage(res.getProductImage().split(",")[0]);
                }
            });
            Map<Long, List<AppAfterSalesDetailRespVO>> afterSalesDetailRespVOMap = afterSalesDetailRespVOS
                    .stream().collect(Collectors.groupingBy(AppAfterSalesDetailRespVO::getAfterSalesId));
            result.forEach(res -> res.setDetails(afterSalesDetailRespVOMap.get(res.getId())));
        }
        return new TableDataInfo(result, PageUtils.getTotal(result));
    }

    private AppAfterSalesPageReqVO setStates(AppAfterSalesPageReqVO vo) {
        List<Integer> states = new ArrayList<>();
        switch (AfterSalesSearchTypeEnum.toEnum(vo.getState())) {
            case IN_PROGRESS:
                states.addAll(Arrays.asList(AfterSalesStatusEnum.AWAITING_AUDIT.getValue(),
                        AfterSalesStatusEnum.AWAITING_SHIPMENT.getValue(),
                        AfterSalesStatusEnum.AWAITING_RECEIPT.getValue()));
                break;
            case COMPLETE:
                states.add(AfterSalesStatusEnum.COMPLETED.getValue());
                break;
            case ALL:
        }
        vo.setStates(states);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void send(AppAfterSalesSendReqVO vo) {
        Long id = vo.getId();
        Long userId = vo.getUserId();
        AfterSales afterSales = getAfterSalesById(id);
        // 校验是否为本人售后单
        verifyMyselfOrder(userId, afterSales.getUserId());
        AfterSales updataAfterSales = AfterSalesConvert.INSTANCE.convert(vo);
        updataAfterSales.setState(AfterSalesStatusEnum.AWAITING_RECEIPT.getValue());
        this.afterSaleUpdateById(updataAfterSales);
        // 保存售后操作记录
        this.saveAfterSalesOperateLog(id, OrderOperateUserTypeEnum.USER, userId, GOODS_RETURNED);
        //注册物流单号
        logisticsLogService.register(id, LogisticsOrderTypeEnum.AFTER_SALE_ORDER.getCode(), vo.getDeliverySn(), vo.getDeliveryName(), vo.getShipperCode());
    }

    //更新售后订单
    private void afterSaleUpdateById(AfterSales updateAfterSale) {
        afterSalesMapper.updateById(updateAfterSale);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(Long afterSalesId, Long userId) {
        AfterSales afterSales = getAfterSalesById(afterSalesId);
        // 校验是否为本人售后单
        verifyMyselfOrder(userId, afterSales.getUserId());
        this.afterSaleUpdateById(AfterSales.builder()
                .id(afterSalesId)
                .state(AfterSalesStatusEnum.USER_CANCELED.getValue())
                .build()
        );
        // 修改明细状态
        orderDetailMapper.update(null, new LambdaUpdateWrapper<OrderDetail>()
                .eq(OrderDetail::getAfterSalesId, afterSalesId)
                .set(OrderDetail::getState, OrderDetailStateEnum.NORMAL.getValue())
                .set(OrderDetail::getAfterSalesId, null)
        );
        // 删除售后明细
        afterSalesDetailMapper.deleteByAfterSalesId(afterSalesId);
        // 保存售后操作记录
        this.saveAfterSalesOperateLog(afterSalesId, OrderOperateUserTypeEnum.USER, userId, USER_CANCELED);
    }

    @Override
    public void remove(Long afterSalesId, Long userId) {
        AfterSales afterSales = getAfterSalesById(afterSalesId);
        Integer state = afterSales.getState();
        if (AfterSalesStatusEnum.COMPLETED.getValue().equals(state) ||
                AfterSalesStatusEnum.BUSINESS_REFUSE.getValue().equals(state) ||
                AfterSalesStatusEnum.USER_CANCELED.getValue().equals(state)
        ) {
            // 校验是否为本人售后单
            verifyMyselfOrder(userId, afterSales.getUserId());
            AfterSales build = AfterSales.builder().id(afterSalesId).userDel(AfterSalesDelEnum.YES.getValue()).build();
            this.afterSaleUpdateById(build);
            return;
        }
        throw ServiceExceptionUtil.exception(SALES_NOT_DEL_ERROR);
    }

    //通过id查询售后订单
    private AfterSales getAfterSalesById(Long id) {
        AfterSales afterSales = afterSalesMapper.selectById(id);
        if (ObjectUtil.isNull(afterSales))
            throw ServiceExceptionUtil.exception(AFTER_SALES_NOT_EXIST_ERROR);
        return afterSales;
    }

    /**
     * 校验操作权限
     *
     * @param loginUserId
     * @param targetUserId
     */
    private void verifyMyselfOrder(Long loginUserId, Long targetUserId) {
        if (!loginUserId.equals(targetUserId) && !loginUserId.equals(0L))
            throw ServiceExceptionUtil.exception(NOT_MYSELF_ORDER_ERROR);
    }

}
